﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MipsPipelineSimulator
{
    public partial class CodeControl : UserControl
    {
        private Control mainForm = null;

        private string[] supportedCodes = new string[] {
            //算术运算指令
            "ADD","ADDU","SUB","SUBU","MUL","SLT","SLTU","ADDI","ADDIU","SLTI","SLTIU","DADD","DADDI",
            "DADDU","DADDIU","DSUB","DSUBU",
            //逻辑运算指令
            "AND","NOR","OR","XOR","ANDI","ORI","XORI",
            //移位运算指令
            "SLL","SRL","SLLV","SRLV","DSLL","DSRL","DSLLV","DSRLV",
            //分支指令
            "BEQZ","BNEZ",
            //访存指令
            "LB","LH","LW","LBU","LHU","LWU","LD","SD","SB","SH","SW",
            //浮点运算指令
            "ADD.S","ADD.D","SUB.S","SUB.D","MUL.S","MUL.D","DIV.S","DIV.D",
            //浮点访存指令
            "LDC1","LWC1","SDC1","SWC1"
        };

        public CodeControl(Control mainForm)
        {
            this.mainForm = mainForm;
            InitializeComponent();
        }

        private void CodeControl_Load(object sender, EventArgs e)
        {
            codeTextBox.Height = this.Height - 60;
            executeButton.Top = this.Height - 50;
        }

        private void executeButton_Click(object sender, EventArgs e)
        {
            if (MasterSwitch.IsRunning())
            {
                DefinedMsgBox msgBox = new DefinedMsgBox("错误", "正在运行上一段程序，请稍等!");
                msgBox.ShowDialog(this);
                return;
            }

            if (codeTextBox.Text == null || codeTextBox.Text == "")
            {
                DefinedMsgBox msgBox = new DefinedMsgBox("错误", "代码不可以为空!");
                msgBox.ShowDialog(this);
                return;
            }
            string[] codes = codeTextBox.Text.Split(new string[1] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            if (codes == null || codes.Length <= 0)
            {
                DefinedMsgBox msgBox = new DefinedMsgBox("错误", "代码不可以为空!");
                msgBox.ShowDialog(this);
                return;
            }
            RunTimeCode.Clear();
            for (int i = 0; i < codes.Length; i++)
            {
                string line = (i + 1).ToString();
                Code code = this.Resolve(codes[i]);
                if (code.codeType == CodeType.ERR)
                {
                    DefinedMsgBox msgBox = new DefinedMsgBox("错误", "第" + line + "条代码有错!");
                    msgBox.ShowDialog(this);
                    return;
                }
                if (code.codeType == CodeType.UNSUPPOTED)
                {
                    DefinedMsgBox msgBox = new DefinedMsgBox("错误", "第" + line + "条代码有错,\n该指令暂时不支持!");
                    msgBox.ShowDialog(this);
                    return;
                }
                RunTimeCode.Add(code);
            }
            MasterSwitch.Start((MainForm)this.mainForm);
        }

        private Code Resolve(string codeStr)
        {
            string[] sections = codeStr.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            if (sections == null || sections.Length != 2)
            {
                return new Code(CodeType.ERR, null);
            }
            if (!supportedCodes.Contains(sections[0]))
            {
                return new Code(CodeType.UNSUPPOTED, null);
            }
            switch (sections[0])
            {
                case "ADD":
                    {
                        return this.ThreeRigistersType(CodeType.ADD, sections[1]);
                    }
                case "ADDU":
                    {
                        return this.ThreeRigistersType(CodeType.ADDU, sections[1]);
                    }
                case "SUB":
                    {
                        return this.ThreeRigistersType(CodeType.SUB, sections[1]);
                    }
                case "SUBU":
                    {
                        return this.ThreeRigistersType(CodeType.SUBU, sections[1]);
                    }
                case "MUL":
                    {
                        return this.ThreeRigistersType(CodeType.MUL, sections[1]);
                    }
                case "SLT":
                    {
                        return this.ThreeRigistersType(CodeType.SLT, sections[1]);
                    }
                case "SLTU":
                    {
                        return this.ThreeRigistersType(CodeType.SLTU, sections[1]);
                    }
                case "ADDI":
                    {
                        return this.TwoRigistersImmediateType(CodeType.ADDI, sections[1], true);
                    }
                case "ADDIU":
                    {
                        return this.TwoRigistersImmediateType(CodeType.ADDIU, sections[1], false);
                    }
                case "SLTI":
                    {
                        return this.TwoRigistersImmediateType(CodeType.SLTI, sections[1], true);
                    }
                case "SLTIU":
                    {
                        return this.TwoRigistersImmediateType(CodeType.SLTIU, sections[1], false);
                    }
                case "DADD":
                    {
                        return this.ThreeRigistersType(CodeType.DADD, sections[1]);
                    }
                case "DADDU":
                    {
                        return this.ThreeRigistersType(CodeType.DADDU, sections[1]);
                    }
                case "DADDI":
                    {
                        return this.TwoRigistersImmediateType(CodeType.DADDI, sections[1], true);
                    }
                case "DADDIU":
                    {
                        return this.TwoRigistersImmediateType(CodeType.DADDIU, sections[1], false);
                    }
                case "DSUB":
                    {
                        return this.ThreeRigistersType(CodeType.DSUB, sections[1]);
                    }
                case "DSUBU":
                    {
                        return this.ThreeRigistersType(CodeType.DSUBU, sections[1]);
                    }
                case "AND":
                    {
                        return this.ThreeRigistersType(CodeType.AND, sections[1]);
                    }
                case "NOR":
                    {
                        return this.ThreeRigistersType(CodeType.NOR, sections[1]);
                    }
                case "OR":
                    {
                        return this.ThreeRigistersType(CodeType.OR, sections[1]);
                    }
                case "XOR":
                    {
                        return this.ThreeRigistersType(CodeType.XOR, sections[1]);
                    }
                case "ANDI":
                    {
                        return this.TwoRigistersImmediateType(CodeType.ANDI, sections[1], true);
                    }
                case "ORI":
                    {
                        return this.TwoRigistersImmediateType(CodeType.ORI, sections[1], true);
                    }
                case "XORI":
                    {
                        return this.TwoRigistersImmediateType(CodeType.XORI, sections[1], true);
                    }
                case "SLL":
                    {
                        return this.TwoRigistersImmediateType(CodeType.SLL, sections[1], true);
                    }
                case "SRA":
                    {
                        return this.TwoRigistersImmediateType(CodeType.SRA, sections[1], true);
                    }
                case "SRL":
                    {
                        return this.TwoRigistersImmediateType(CodeType.SRL, sections[1], true);
                    }
                case "SLLV":
                    {
                        return this.ThreeRigistersType(CodeType.SLLV, sections[1]);
                    }
                case "SRAV":
                    {
                        return this.ThreeRigistersType(CodeType.SRAV, sections[1]);
                    }
                case "SRLV":
                    {
                        return this.ThreeRigistersType(CodeType.SRLV, sections[1]);
                    }
                case "DSLL":
                    {
                        return this.TwoRigistersImmediateType(CodeType.DSLL, sections[1],true);
                    }
                case "DSRL":
                    {
                        return this.TwoRigistersImmediateType(CodeType.DSRL, sections[1], true);
                    }
                case "DSRA":
                    {
                        return this.TwoRigistersImmediateType(CodeType.DSRA, sections[1], true);
                    }
                case "DSLLV":
                    {
                        return this.ThreeRigistersType(CodeType.DSLLV, sections[1]);
                    }
                case "DSRLV":
                    {
                        return this.ThreeRigistersType(CodeType.DSRLV, sections[1]);
                    }
                case "DSRAV":
                    {
                        return this.ThreeRigistersType(CodeType.DSRAV, sections[1]);
                    }
                case "BEQZ":
                    {
                        return this.OneRigisterImmediateType(CodeType.BEQZ, sections[1], true);
                    }
                case "BNEZ":
                    {
                        return this.OneRigisterImmediateType(CodeType.BNEZ, sections[1], true);
                    }
                case "LB":
                    {
                        return this.TwoRigistersBaseType(CodeType.LB, sections[1], true);
                    }
                case "LH":
                    {
                        return this.TwoRigistersBaseType(CodeType.LH, sections[1], true);
                    }
                case "LW":
                    {
                        return this.TwoRigistersBaseType(CodeType.LW, sections[1], true);
                    }
                case "LBU":
                    {
                        return this.TwoRigistersBaseType(CodeType.LBU, sections[1], true);
                    }
                case "LHU":
                    {
                        return this.TwoRigistersBaseType(CodeType.LB, sections[1], true);
                    }
                case "LWU":
                    {
                        return this.TwoRigistersBaseType(CodeType.LB, sections[1], true);
                    }
                case "LD":
                    {
                        return this.TwoRigistersBaseType(CodeType.LD, sections[1], true);
                    }
                case "SD":
                    {
                        return this.TwoRigistersBaseType(CodeType.SD, sections[1], true);
                    }
                case "SB":
                    {
                        return this.TwoRigistersBaseType(CodeType.SB, sections[1], true);
                    }
                case "SH":
                    {
                        return this.TwoRigistersBaseType(CodeType.SH, sections[1], true);
                    }
                case "SW":
                    {
                        return this.TwoRigistersBaseType(CodeType.SW, sections[1], true);
                    }
                case "ADD.S":
                    {
                        return this.ThreeRigistersType(CodeType.ADD_S, sections[1]);
                    }
                case "ADD.D":
                    {
                        return this.ThreeRigistersType(CodeType.ADD_D, sections[1]);
                    }
                case "SUB.S":
                    {
                        return this.ThreeRigistersType(CodeType.SUB_S, sections[1]);
                    }
                case "SUB.D":
                    {
                        return this.ThreeRigistersType(CodeType.SUB_D, sections[1]);
                    }
                case "MUL.S":
                    {
                        return this.ThreeRigistersType(CodeType.MUL_S, sections[1]);
                    }
                case "MUL.D":
                    {
                        return this.ThreeRigistersType(CodeType.MUL_D, sections[1]);
                    }
                case "DIV.S":
                    {
                        return this.ThreeRigistersType(CodeType.DIV_S, sections[1]);
                    }
                case "DIV.D":
                    {
                        return this.ThreeRigistersType(CodeType.DIV_D, sections[1]);
                    }
                case "LDC1":
                    {
                        return this.TwoRigistersBaseType(CodeType.LDC1, sections[1], true);
                    }
                case "LWC1":
                    {
                        return this.TwoRigistersBaseType(CodeType.LWC1, sections[1], true);
                    }
                case "SDC1":
                    {
                        return this.TwoRigistersBaseType(CodeType.SDC1, sections[1], true);
                    }
                case "SWC1":
                    {
                        return this.TwoRigistersBaseType(CodeType.SWC1, sections[1], true);
                    }
            }

            return new Code(CodeType.ERR, null); ;
        }

        private Code ThreeRigistersType(CodeType codeType, string argsStr)
        {
            Code code = new Code();
            if (argsStr == null)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            string[] argsSections = argsStr.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (argsSections == null || argsSections.Length != 3)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            foreach (string arg in argsSections)
            {
                if (!((MainForm)mainForm).commandForm.registerControl.IfExsit(arg))
                {
                    code.codeType = CodeType.ERR;
                    return code;
                }
            }
            code.codeType = codeType;
            code.args = new object[3] { argsSections[1], argsSections[2], argsSections[0] };
            return code;
        }

        private Code TwoRigistersImmediateType(CodeType codeType, string argsStr, bool numType)
        {
            Code code = new Code();
            if (argsStr == null)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            string[] argsSections = argsStr.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (argsSections == null || argsSections.Length != 3)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            for (int i = 0; i < 2; i++)
            {
                if (!((MainForm)mainForm).commandForm.registerControl.IfExsit(argsSections[i]))
                {
                    code.codeType = CodeType.ERR;
                    return code;
                }
            }
            object arg3 = null;
            if (numType) arg3 = CommonTool.StrToNum(TypeCode.Int16, argsSections[2], 10);
            else arg3 = CommonTool.StrToNum(TypeCode.UInt16, argsSections[2], 10);
            if (arg3 == null)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            code.codeType = codeType;
            code.args = new object[3] { argsSections[1], arg3, argsSections[0] };
            return code;
        }

        private Code OneRigisterImmediateType(CodeType codeType, string argsStr, bool numType)
        {
            Code code = new Code();
            if (argsStr == null)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            string[] argsSections = argsStr.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (argsSections == null || argsSections.Length != 2)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            for (int i = 0; i < 1; i++)
            {
                if (!((MainForm)mainForm).commandForm.registerControl.IfExsit(argsSections[i]))
                {
                    code.codeType = CodeType.ERR;
                    return code;
                }
            }
            object arg2 = null;
            if (numType) arg2 = CommonTool.StrToNum(TypeCode.Int16, argsSections[1], 10);
            else arg2 = CommonTool.StrToNum(TypeCode.UInt16, argsSections[1], 10);
            if (arg2 == null)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            code.codeType = codeType;
            code.args = new object[2] { argsSections[0], arg2 };
            return code;
        }

        private Code TwoRigistersBaseType(CodeType codeType, string argsStr, bool numType)
        {
            Code code = new Code();
            if (argsStr == null)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            string[] argsSections = argsStr.Split(new char[3] { ',', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
            if (argsSections == null || argsSections.Length != 3)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            if (!((MainForm)mainForm).commandForm.registerControl.IfExsit(argsSections[0]))
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            if (!((MainForm)mainForm).commandForm.registerControl.IfExsit(argsSections[2]))
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            object arg3 = null;
            if (numType) arg3 = CommonTool.StrToNum(TypeCode.Int16, argsSections[1], 10);
            else arg3 = CommonTool.StrToNum(TypeCode.UInt16, argsSections[1], 10);
            if (arg3 == null)
            {
                code.codeType = CodeType.ERR;
                return code;
            }
            code.codeType = codeType;
            code.args = new object[3] { argsSections[2], arg3, argsSections[0] };
            return code;
        }
    }
}
